use serde::Deserialize;
use rust_decimal::Decimal;
use crate::rest::{DepthLevel, ExchangeInfo, OrderBook};

/// ========================
/// MarketStreamEvent 枚举
/// ========================
#[derive(Debug, Clone)]
pub enum TimerType {
    OrderBookRebuild,
    ExchangeInfoRefresh(ExchangeInfo),
    Custom(String), // 备用扩展
}

#[derive(Debug, Clone, Deserialize)]
pub enum MarketStreamEvent {
    BookTicker(BookTickerEvent),
    MarkPrice(MarkPriceEvent),
    ForceOrder(ForceOrderEvent),
    DepthUpdate(DepthUpdate),
    AggTrade(AggTrade),
    Kline(Kline),
    OrderBook(OrderBook),
}

/// ========================
/// BookTickerEvent（三段）
/// ========================
#[derive(Debug, Deserialize)]
pub struct BookTickerRaw {
    pub e: String, // event type
    pub u: u64,    // update id
    pub E: u64,    // event time
    pub T: u64,    // transaction time
    pub s: String, // symbol
    pub b: String, // bid price
    pub B: String, // bid quantity
    pub a: String, // ask price
    pub A: String, // ask quantity
}

impl BookTickerRaw {
    pub fn to_model(self) -> Option<BookTickerEvent> {
        Some(BookTickerEvent {
            symbol: self.s,
            bid_price: self.b.parse().ok()?,
            bid_qty: self.B.parse().ok()?,
            ask_price: self.a.parse().ok()?,
            ask_qty: self.A.parse().ok()?,
            event_time: self.E,
            transaction_time: self.T,
            update_id: self.u,
        })
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct BookTickerEvent {
    pub symbol: String,
    pub bid_price: Decimal,
    pub bid_qty: Decimal,
    pub ask_price: Decimal,
    pub ask_qty: Decimal,
    pub event_time: u64,
    pub transaction_time: u64,
    pub update_id: u64,
}

/// ========================
/// MarkPriceEvent（三段）
/// ========================
#[derive(Debug, Deserialize)]
pub struct MarkPriceRaw {
    pub e: String, // event type
    pub E: u64,    // event time
    pub s: String, // symbol
    pub p: String, // mark price
    pub i: String, // index price
    pub P: String, // estimated settle price
    pub r: String, // funding rate
    pub T: u64,    // next funding time
}

impl MarkPriceRaw {
    pub fn to_model(self) -> Option<MarkPriceEvent> {
        Some(MarkPriceEvent {
            symbol: self.s,
            mark_price: self.p.parse().ok()?,
            index_price: self.i.parse().ok()?,
            estimated_settle_price: self.P.parse().ok()?,
            funding_rate: self.r.parse().ok()?,
            event_time: self.E,
            next_funding_time: self.T,
        })
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct MarkPriceEvent {
    pub symbol: String,
    pub mark_price: Decimal,
    pub index_price: Decimal,
    pub estimated_settle_price: Decimal,
    pub funding_rate: Decimal,
    pub event_time: u64,
    pub next_funding_time: u64,
}

/// ========================
/// ForceOrderDetailRaw → ForceOrderDetail
/// ========================

#[derive(Debug, Deserialize)]
pub struct ForceOrderDetailRaw {
    pub s: String,
    pub S: String,
    pub o: String,
    pub f: String,
    pub q: String,
    pub p: String,
    pub ap: String,
    pub X: String,
    pub l: String,
    pub z: String,
    pub T: u64,
}

impl ForceOrderDetailRaw {
    pub fn to_model(&self) -> Option<ForceOrderDetail> {
        Some(ForceOrderDetail {
            symbol: self.s.clone(),
            side: self.S.clone(),
            order_type: self.o.clone(),
            time_in_force: self.f.clone(),
            quantity: self.q.parse().ok()?,
            price: self.p.parse().ok()?,
            avg_price: self.ap.parse().ok()?,
            status: self.X.clone(),
            last_filled_qty: self.l.parse().ok()?,
            cum_filled_qty: self.z.parse().ok()?,
            trade_time: self.T,
        })
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct ForceOrderDetail {
    pub symbol: String,
    pub side: String,
    pub order_type: String,
    pub time_in_force: String,
    pub quantity: Decimal,
    pub price: Decimal,
    pub avg_price: Decimal,
    pub status: String,
    pub last_filled_qty: Decimal,
    pub cum_filled_qty: Decimal,
    pub trade_time: u64,
}

/// ========================
/// ForceOrderRaw → ForceOrderEvent
/// ========================

#[derive(Debug, Deserialize)]
pub struct ForceOrderRaw {
    pub e: String,
    pub E: u64,
    pub o: ForceOrderDetailRaw,
}

impl ForceOrderRaw {
    pub fn to_model(self) -> Option<ForceOrderEvent> {
        Some(ForceOrderEvent {
            event_time: self.E,
            detail: self.o.to_model()?,
        })
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct ForceOrderEvent {
    pub event_time: u64,
    pub detail: ForceOrderDetail,
}

/// ========================
/// DepthUpdateRaw → DepthUpdate
/// ========================

#[derive(Debug, Deserialize)]
pub struct DepthUpdateRaw {
    pub e: String,
    pub E: u64,
    pub T: u64,
    pub s: String,
    pub U: u64,
    pub u: u64,
    #[serde(rename = "pu")]
    pub pu: Option<u64>,
    pub b: Vec<[String; 2]>,
    pub a: Vec<[String; 2]>,
}

impl DepthUpdateRaw {
    pub fn to_model(self) -> Option<DepthUpdate> {
        Some(DepthUpdate {
            symbol: self.s,
            event_time: self.E,
            transaction_time: self.T,
            first_update_id: self.U,
            final_update_id: self.u,
            previous_final_update_id: self.pu,
            bids: self.b
                .iter()
                .filter_map(|[price, qty]| {
                    Some(DepthLevel {
                        price: Decimal::from_str_exact(price).unwrap(),
                        qty: Decimal::from_str_exact(qty).unwrap(),
                    })
                })
                .collect(),
            asks: self.a
                .iter()
                .filter_map(|[price, qty]| {
                    Some(DepthLevel {
                        price: Decimal::from_str_exact(price).unwrap(),
                        qty: Decimal::from_str_exact(qty).unwrap(),
                    })
                })
                .collect(),
        })
    }
}

/// ========================
/// DepthUpdate
/// ========================

#[derive(Debug, Clone, Deserialize)]
pub struct DepthUpdate {
    pub symbol: String,
    pub event_time: u64,
    pub transaction_time: u64,
    pub first_update_id: u64,
    pub final_update_id: u64,
    pub previous_final_update_id: Option<u64>,
    pub bids: Vec<DepthLevel>,
    pub asks: Vec<DepthLevel>,
}

/// ========================
/// AggTradeRaw → AggTrade
/// ========================

#[derive(Debug, Deserialize)]
pub struct AggTradeRaw {
    pub e: String,  // "aggTrade"
    pub E: u64,     // Event time
    pub s: String,  // Symbol
    pub a: u64,     // Aggregate trade ID
    pub p: String,  // Price
    pub q: String,  // Quantity
    pub f: u64,     // First trade ID
    pub l: u64,     // Last trade ID
    pub T: u64,     // Trade time
    pub m: bool,    // Is buyer the market maker?
}

impl AggTradeRaw {
    pub fn to_model(&self) -> Option<AggTrade> {
        Some(AggTrade {
            symbol: self.s.clone(),
            agg_trade_id: self.a,
            price: self.p.parse().ok()?,
            quantity: self.q.parse().ok()?,
            first_trade_id: self.f,
            last_trade_id: self.l,
            trade_time: self.T,
            is_buyer_maker: self.m,
        })
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct AggTrade {
    pub symbol: String,
    pub agg_trade_id: u64,
    pub price: Decimal,
    pub quantity: Decimal,
    pub first_trade_id: u64,
    pub last_trade_id: u64,
    pub trade_time: u64,
    pub is_buyer_maker: bool,
}

/// ========================
/// KlineRaw → Kline
/// ========================

#[derive(Debug, Deserialize)]
pub struct KlineRaw {
    pub e: String,    // "kline"
    pub E: u64,       // Event time
    pub s: String,    // Symbol
    pub k: KlineDetailRaw,
}

#[derive(Debug, Deserialize)]
pub struct KlineDetailRaw {
    pub t: u64,        // 开始时间
    pub T: u64,        // 结束时间
    pub s: String,     // Symbol
    pub i: String,     // Interval
    pub f: u64,        // First trade ID
    pub L: u64,        // Last trade ID
    pub o: String,     // Open
    pub c: String,     // Close
    pub h: String,     // High
    pub l: String,     // Low
    pub v: String,     // 成交量 base
    pub n: u64,        // 成交笔数
    pub x: bool,       // 是否收盘
    pub q: String,     // 成交额 quote
    pub V: String,     // 主动买入 base 量
    pub Q: String,     // 主动买入 quote 额
    pub B: String,     // 忽略字段
}

impl KlineRaw {
    pub fn to_model(&self) -> Option<Kline> {
        self.k.to_model()
    }
}

impl KlineDetailRaw {
    pub fn to_model(&self) -> Option<Kline> {
        Some(Kline {
            symbol: self.s.clone(),
            interval: self.i.clone(),
            start_time: self.t,
            end_time: self.T,
            open: self.o.parse().ok()?,
            close: self.c.parse().ok()?,
            high: self.h.parse().ok()?,
            low: self.l.parse().ok()?,
            volume: self.v.parse().ok()?,
            trades: self.n,
            is_closed: self.x,
            quote_volume: self.q.parse().ok()?,
            taker_base_volume: self.V.parse().ok()?,
            taker_quote_volume: self.Q.parse().ok()?,
        })
    }
}

/// ========================
/// Kline
/// ========================

#[derive(Debug, Clone, Deserialize)]
pub struct Kline {
    pub symbol: String,
    pub interval: String,
    pub start_time: u64,
    pub end_time: u64,
    pub open: Decimal,
    pub close: Decimal,
    pub high: Decimal,
    pub low: Decimal,
    pub volume: Decimal,
    pub trades: u64,
    pub is_closed: bool,
    pub quote_volume: Decimal,
    pub taker_base_volume: Decimal,
    pub taker_quote_volume: Decimal,
}